home *** CD-ROM | disk | FTP | other *** search
/ CD/PC Actual 31 / PC Actual CD 31.iso / dists / SRC / SLIBEXEC.AA / SLIBEXEC / libexec / rbootd / bpf.c next >
Encoding:
C/C++ Source or Header  |  1997-11-24  |  10.5 KB  |  423 lines

  1. /*
  2.  * Copyright (c) 1988, 1992 The University of Utah and the Center
  3.  *    for Software Science (CSS).
  4.  * Copyright (c) 1992, 1993
  5.  *    The Regents of the University of California.  All rights reserved.
  6.  *
  7.  * This code is derived from software contributed to Berkeley by
  8.  * the Center for Software Science of the University of Utah Computer
  9.  * Science Department.  CSS requests users of this software to return
  10.  * to css-dist@cs.utah.edu any improvements that they make and grant
  11.  * CSS redistribution rights.
  12.  *
  13.  * Redistribution and use in source and binary forms, with or without
  14.  * modification, are permitted provided that the following conditions
  15.  * are met:
  16.  * 1. Redistributions of source code must retain the above copyright
  17.  *    notice, this list of conditions and the following disclaimer.
  18.  * 2. Redistributions in binary form must reproduce the above copyright
  19.  *    notice, this list of conditions and the following disclaimer in the
  20.  *    documentation and/or other materials provided with the distribution.
  21.  * 3. All advertising materials mentioning features or use of this software
  22.  *    must display the following acknowledgement:
  23.  *    This product includes software developed by the University of
  24.  *    California, Berkeley and its contributors.
  25.  * 4. Neither the name of the University nor the names of its contributors
  26.  *    may be used to endorse or promote products derived from this software
  27.  *    without specific prior written permission.
  28.  *
  29.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  30.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  31.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  32.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  33.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  34.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  35.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  36.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  37.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  38.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  39.  * SUCH DAMAGE.
  40.  *
  41.  *    from: @(#)bpf.c    8.1 (Berkeley) 6/4/93
  42.  *
  43.  * From: Utah Hdr: bpf.c 3.1 92/07/06
  44.  * Author: Jeff Forys, University of Utah CSS
  45.  */
  46.  
  47. #ifndef lint
  48. #if 0
  49. static const char sccsid[] = "@(#)bpf.c    8.1 (Berkeley) 6/4/93";
  50. #endif
  51. static const char rcsid[] =
  52.     "$Id: bpf.c,v 1.9 1997/11/24 07:33:39 charnier Exp $";
  53. #endif /* not lint */
  54.  
  55. #include <sys/param.h>
  56. #include <sys/ioctl.h>
  57. #include <sys/socket.h>
  58. #include <sys/time.h>
  59.  
  60. #include <net/if.h>
  61. #include <net/bpf.h>
  62.  
  63. #include <ctype.h>
  64. #include <errno.h>
  65. #include <fcntl.h>
  66. #include <stdio.h>
  67. #include <stdlib.h>
  68. #include <string.h>
  69. #include <syslog.h>
  70. #include <unistd.h>
  71. #include "defs.h"
  72. #include "pathnames.h"
  73.  
  74. static int BpfFd = -1;
  75. static unsigned BpfLen = 0;
  76. static u_int8_t *BpfPkt = NULL;
  77.  
  78. /*
  79. **  BpfOpen -- Open and initialize a BPF device.
  80. **
  81. **    Parameters:
  82. **        None.
  83. **
  84. **    Returns:
  85. **        File descriptor of opened BPF device (for select() etc).
  86. **
  87. **    Side Effects:
  88. **        If an error is encountered, the program terminates here.
  89. */
  90. int
  91. BpfOpen()
  92. {
  93.     struct ifreq ifr;
  94.     char bpfdev[32];
  95.     int n = 0;
  96.  
  97.     /*
  98.      *  Open the first available BPF device.
  99.      */
  100.     do {
  101.         (void) sprintf(bpfdev, _PATH_BPF, n++);
  102.         BpfFd = open(bpfdev, O_RDWR);
  103.     } while (BpfFd < 0 && (errno == EBUSY || errno == EPERM));
  104.  
  105.     if (BpfFd < 0) {
  106.         syslog(LOG_ERR, "bpf: no available devices: %m");
  107.         Exit(0);
  108.     }
  109.  
  110.     /*
  111.      *  Set interface name for bpf device, get data link layer
  112.      *  type and make sure it's type Ethernet.
  113.      */
  114.     (void) strncpy(ifr.ifr_name, IntfName, sizeof(ifr.ifr_name));
  115.     if (ioctl(BpfFd, BIOCSETIF, (caddr_t)&ifr) < 0) {
  116.         syslog(LOG_ERR, "bpf: ioctl(BIOCSETIF,%s): %m", IntfName);
  117.         Exit(0);
  118.     }
  119.  
  120.     /*
  121.      *  Make sure we are dealing with an Ethernet device.
  122.      */
  123.     if (ioctl(BpfFd, BIOCGDLT, (caddr_t)&n) < 0) {
  124.         syslog(LOG_ERR, "bpf: ioctl(BIOCGDLT): %m");
  125.         Exit(0);
  126.     }
  127.     if (n != DLT_EN10MB) {
  128.         syslog(LOG_ERR,"bpf: %s: data-link type %d unsupported",
  129.                IntfName, n);
  130.         Exit(0);
  131.     }
  132.  
  133.     /*
  134.      *  On read(), return packets immediately (do not buffer them).
  135.      */
  136.     n = 1;
  137.     if (ioctl(BpfFd, BIOCIMMEDIATE, (caddr_t)&n) < 0) {
  138.         syslog(LOG_ERR, "bpf: ioctl(BIOCIMMEDIATE): %m");
  139.         Exit(0);
  140.     }
  141.  
  142.     /*
  143.      *  Try to enable the chip/driver's multicast address filter to
  144.      *  grab our RMP address.  If this fails, try promiscuous mode.
  145.      *  If this fails, there's no way we are going to get any RMP
  146.      *  packets so just exit here.
  147.      */
  148. #ifdef MSG_EOR
  149.     ifr.ifr_addr.sa_len = RMP_ADDRLEN + 2;
  150. #endif
  151.     ifr.ifr_addr.sa_family = AF_UNSPEC;
  152.     memmove((char *)&ifr.ifr_addr.sa_data[0], &RmpMcastAddr[0], RMP_ADDRLEN);
  153.     if (ioctl(BpfFd, BIOCPROMISC, (caddr_t)0) < 0) {
  154.         syslog(LOG_ERR, "bpf: can't set promiscuous mode: %m");
  155.         Exit(0);
  156.     }
  157.  
  158.     /*
  159.      *  Ask BPF how much buffer space it requires and allocate one.
  160.      */
  161.     if (ioctl(BpfFd, BIOCGBLEN, (caddr_t)&BpfLen) < 0) {
  162.         syslog(LOG_ERR, "bpf: ioctl(BIOCGBLEN): %m");
  163.         Exit(0);
  164.     }
  165.     if (BpfPkt == NULL)
  166.         BpfPkt = (u_int8_t *)malloc(BpfLen);
  167.  
  168.     if (BpfPkt == NULL) {
  169.         syslog(LOG_ERR, "bpf: out of memory (%u bytes for bpfpkt)",
  170.                BpfLen);
  171.         Exit(0);
  172.     }
  173.  
  174.     /*
  175.      *  Write a little program to snarf RMP Boot packets and stuff
  176.      *  it down BPF's throat (i.e. set up the packet filter).
  177.      */
  178.     {
  179. #define    RMP    ((struct rmp_packet *)0)
  180.         static struct bpf_insn bpf_insn[] = {
  181.             { BPF_LD|BPF_B|BPF_ABS,  0, 0, (long)&RMP->hp_llc.dsap },
  182.             { BPF_JMP|BPF_JEQ|BPF_K, 0, 5, IEEE_DSAP_HP },
  183.             { BPF_LD|BPF_H|BPF_ABS,  0, 0, (long)&RMP->hp_llc.cntrl },
  184.             { BPF_JMP|BPF_JEQ|BPF_K, 0, 3, IEEE_CNTL_HP },
  185.             { BPF_LD|BPF_H|BPF_ABS,  0, 0, (long)&RMP->hp_llc.dxsap },
  186.             { BPF_JMP|BPF_JEQ|BPF_K, 0, 1, HPEXT_DXSAP },
  187.             { BPF_RET|BPF_K,         0, 0, RMP_MAX_PACKET },
  188.             { BPF_RET|BPF_K,         0, 0, 0x0 }
  189.         };
  190. #undef    RMP
  191.         static struct bpf_program bpf_pgm = {
  192.             sizeof(bpf_insn)/sizeof(bpf_insn[0]), bpf_insn
  193.         };
  194.  
  195.         if (ioctl(BpfFd, BIOCSETF, (caddr_t)&bpf_pgm) < 0) {
  196.             syslog(LOG_ERR, "bpf: ioctl(BIOCSETF): %m");
  197.             Exit(0);
  198.         }
  199.     }
  200.  
  201.     return(BpfFd);
  202. }
  203.  
  204. /*
  205. **  BPF GetIntfName -- Return the name of a network interface attached to
  206. **        the system, or 0 if none can be found.  The interface
  207. **        must be configured up; the lowest unit number is
  208. **        preferred; loopback is ignored.
  209. **
  210. **    Parameters:
  211. **        errmsg - if no network interface found, *errmsg explains why.
  212. **
  213. **    Returns:
  214. **        A (static) pointer to interface name, or NULL on error.
  215. **
  216. **    Side Effects:
  217. **        None.
  218. */
  219. char *
  220. BpfGetIntfName(errmsg)
  221.     char **errmsg;
  222. {
  223.     struct ifreq ibuf[8], *ifrp, *ifend, *mp;
  224.     struct ifconf ifc;
  225.     int fd;
  226.     int minunit, n;
  227.     char *cp;
  228.     static char device[sizeof(ifrp->ifr_name)];
  229.     static char errbuf[128] = "No Error!";
  230.  
  231.     if (errmsg != NULL)
  232.         *errmsg = errbuf;
  233.  
  234.     if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
  235.         (void) strcpy(errbuf, "bpf: socket: %m");
  236.         return(NULL);
  237.     }
  238.     ifc.ifc_len = sizeof ibuf;
  239.     ifc.ifc_buf = (caddr_t)ibuf;
  240.  
  241. #ifdef OSIOCGIFCONF
  242.     if (ioctl(fd, OSIOCGIFCONF, (char *)&ifc) < 0 ||
  243.         ifc.ifc_len < sizeof(struct ifreq)) {
  244.         (void) strcpy(errbuf, "bpf: ioctl(OSIOCGIFCONF): %m");
  245.         return(NULL);
  246.     }
  247. #else
  248.     if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 ||
  249.         ifc.ifc_len < sizeof(struct ifreq)) {
  250.         (void) strcpy(errbuf, "bpf: ioctl(SIOCGIFCONF): %m");
  251.         return(NULL);
  252.     }
  253. #endif
  254.     ifrp = ibuf;
  255.     ifend = (struct ifreq *)((char *)ibuf + ifc.ifc_len);
  256.  
  257.     mp = 0;
  258.     minunit = 666;
  259.     for (; ifrp < ifend; ++ifrp) {
  260.         if (ioctl(fd, SIOCGIFFLAGS, (char *)ifrp) < 0) {
  261.             (void) strcpy(errbuf, "bpf: ioctl(SIOCGIFFLAGS): %m");
  262.             return(NULL);
  263.         }
  264.  
  265.         /*
  266.          *  If interface is down or this is the loopback interface,
  267.          *  ignore it.
  268.          */
  269.         if ((ifrp->ifr_flags & IFF_UP) == 0 ||
  270. #ifdef IFF_LOOPBACK
  271.             (ifrp->ifr_flags & IFF_LOOPBACK))
  272. #else
  273.             (strcmp(ifrp->ifr_name, "lo0") == 0))
  274. #endif
  275.             continue;
  276.  
  277.         for (cp = ifrp->ifr_name; !isdigit(*cp); ++cp)
  278.             ;
  279.         n = atoi(cp);
  280.         if (n < minunit) {
  281.             minunit = n;
  282.             mp = ifrp;
  283.         }
  284.     }
  285.  
  286.     (void) close(fd);
  287.     if (mp == 0) {
  288.         (void) strcpy(errbuf, "bpf: no interfaces found");
  289.         return(NULL);
  290.     }
  291.  
  292.     (void) strcpy(device, mp->ifr_name);
  293.     return(device);
  294. }
  295.  
  296. /*
  297. **  BpfRead -- Read packets from a BPF device and fill in `rconn'.
  298. **
  299. **    Parameters:
  300. **        rconn - filled in with next packet.
  301. **        doread - is True if we can issue a read() syscall.
  302. **
  303. **    Returns:
  304. **        True if `rconn' contains a new packet, False otherwise.
  305. **
  306. **    Side Effects:
  307. **        None.
  308. */
  309. int
  310. BpfRead(rconn, doread)
  311.     RMPCONN *rconn;
  312.     int doread;
  313. {
  314.     int datlen, caplen, hdrlen;
  315.     static u_int8_t *bp = NULL, *ep = NULL;
  316.     int cc;
  317.  
  318.     /*
  319.      *  The read() may block, or it may return one or more packets.
  320.      *  We let the caller decide whether or not we can issue a read().
  321.      */
  322.     if (doread) {
  323.         if ((cc = read(BpfFd, (char *)BpfPkt, (int)BpfLen)) < 0) {
  324.             syslog(LOG_ERR, "bpf: read: %m");
  325.             return(0);
  326.         } else {
  327.             bp = BpfPkt;
  328.             ep = BpfPkt + cc;
  329.         }
  330.     }
  331.  
  332. #define bhp ((struct bpf_hdr *)bp)
  333.     /*
  334.      *  If there is a new packet in the buffer, stuff it into `rconn'
  335.      *  and return a success indication.
  336.      */
  337.     if (bp < ep) {
  338.         datlen = bhp->bh_datalen;
  339.         caplen = bhp->bh_caplen;
  340.         hdrlen = bhp->bh_hdrlen;
  341.  
  342.         if (caplen != datlen)
  343.             syslog(LOG_ERR,
  344.                    "bpf: short packet dropped (%d of %d bytes)",
  345.                    caplen, datlen);
  346.         else if (caplen > sizeof(struct rmp_packet))
  347.             syslog(LOG_ERR, "bpf: large packet dropped (%d bytes)",
  348.                    caplen);
  349.         else {
  350.             rconn->rmplen = caplen;
  351.             memmove((char *)&rconn->tstamp, (char *)&bhp->bh_tstamp,
  352.                   sizeof(struct timeval));
  353.             memmove((char *)&rconn->rmp, (char *)bp + hdrlen, caplen);
  354.         }
  355.         bp += BPF_WORDALIGN(caplen + hdrlen);
  356.         return(1);
  357.     }
  358. #undef bhp
  359.  
  360.     return(0);
  361. }
  362.  
  363. /*
  364. **  BpfWrite -- Write packet to BPF device.
  365. **
  366. **    Parameters:
  367. **        rconn - packet to send.
  368. **
  369. **    Returns:
  370. **        True if write succeeded, False otherwise.
  371. **
  372. **    Side Effects:
  373. **        None.
  374. */
  375. int
  376. BpfWrite(rconn)
  377.     RMPCONN *rconn;
  378. {
  379.     if (write(BpfFd, (char *)&rconn->rmp, rconn->rmplen) < 0) {
  380.         syslog(LOG_ERR, "write: %s: %m", EnetStr(rconn));
  381.         return(0);
  382.     }
  383.  
  384.     return(1);
  385. }
  386.  
  387. /*
  388. **  BpfClose -- Close a BPF device.
  389. **
  390. **    Parameters:
  391. **        None.
  392. **
  393. **    Returns:
  394. **        Nothing.
  395. **
  396. **    Side Effects:
  397. **        None.
  398. */
  399. void
  400. BpfClose()
  401. {
  402.     struct ifreq ifr;
  403.  
  404.     if (BpfPkt != NULL) {
  405.         free((char *)BpfPkt);
  406.         BpfPkt = NULL;
  407.     }
  408.  
  409.     if (BpfFd == -1)
  410.         return;
  411.  
  412. #ifdef MSG_EOR
  413.     ifr.ifr_addr.sa_len = RMP_ADDRLEN + 2;
  414. #endif
  415.     ifr.ifr_addr.sa_family = AF_UNSPEC;
  416.     memmove((char *)&ifr.ifr_addr.sa_data[0], &RmpMcastAddr[0], RMP_ADDRLEN);
  417.     if (ioctl(BpfFd, SIOCDELMULTI, (caddr_t)&ifr) < 0)
  418.         (void) ioctl(BpfFd, BIOCPROMISC, (caddr_t)0);
  419.  
  420.     (void) close(BpfFd);
  421.     BpfFd = -1;
  422. }
  423.